package impl;

import java.io.*;
import java.text.*;
import java.util.*;

import org.jsoup.Jsoup;
import org.jsoup.nodes.*;
import org.jsoup.select.Elements;

import dataobj.CourseTO;

/***
 * Implementation of City University of Hong Kong on reading input file.
 */
public class cityuImpl extends UniversityImpl{

	/***
	 * Get the course information from the input file and add to the array list of the course.
	 */
	@Override
	public ArrayList<CourseTO> getCourses(File file) {
		Document doc;
		ArrayList<CourseTO> courses = new ArrayList<>();
		try {
			doc = Jsoup.parse(file, "UTF-8");
			Elements CourseTables = doc.body().getElementsByClass("datadisplaytable");
			for (int i=0; i<CourseTables.size();i+=2){
				Element CourseDetail = CourseTables.get(i);
				Element CourseTime = CourseTables.get(i+1);
				ArrayList<CourseTO> tempCourses = getCourseByElements(CourseDetail, CourseTime);
				if(tempCourses!=null){
					for(CourseTO tempCourse: tempCourses){
						courses.add(tempCourse);
					}
				}
			}

		}catch (Exception e) {
			ui.UI.showErrorMessage("Something went wrong, the file is corrupted!");
			return new ArrayList<CourseTO>();
		}
		return courses;
	}

	/***
	 * Return the courses list with the course detail.
	 * @param courseDetail	the course detail
	 * @param courseTime	the course time detail
	 * @return		the course list
	 */
	private ArrayList<CourseTO> getCourseByElements(Element courseDetail, Element courseTime){
		ArrayList<CourseTO> coursesList = new ArrayList<>();
		String[] captions = courseDetail.getElementsByTag("caption").text().split(" - ");
		Elements details = courseDetail.getElementsByClass("dddefault");
		Elements timeDetails = courseTime.getElementsByTag("tr");
		
		for(int i=1;i<timeDetails.size();i++){
			Elements timeDetail = timeDetails.get(i).getElementsByClass("dddefault");
			//get all the details from Detail Tables
			String name = captions[0];
			String code = captions[1];
			String session = captions[2];
			String crn = details.get(1).text();
			String instructor = details.get(3).text();
			Double credits = Double.parseDouble(details.get(5).text());
			
			//get all the time details from Time Table
			String[] time = timeDetail.get(1).text().split(" - ");
			String[] date = timeDetail.get(4).text().split(" - ");
			String weekDay = timeDetail.get(2).text();
			String venue = timeDetail.get(3).text();
			
			CourseTO course = getCourseTO(name, code, session, crn, instructor, credits, time, date, weekDay, venue);
			if(course!=null)
				coursesList.add(course);
		}
		return coursesList;

	}

	/***
	 * Create the course objects with the course information.
	 * @param name	the course name
	 * @param code	the course code
	 * @param session	the course session
	 * @param crn	the course number
	 * @param instructor	the course instructor's name
	 * @param credits	the credits
	 * @param time	the starting and ending time of the course
	 * @param date	the starting and ending date of the course
	 * @param weekday	the week day of the course
	 * @param venue the venue of the course
	 * @return		the course information
	 */
	private CourseTO getCourseTO(String name, String code, String session,
			String crn, String instructor, Double credits, String[] time,
			String[] date, String weekday, String venue) {

		//handle the courses without time and date
		if(time.length == 1 || date.length == 1) return null;
		
		CourseTO temp = new CourseTO();
		temp.setName(name);
		temp.setCode(code);
		temp.setSession(session);
		temp.setCrn(crn);
		temp.setInstructor(instructor);
		temp.setCredits(credits);
		int weekDay = getWeekDayByChar(weekday);
		temp.setWeekDay(weekDay);
		temp.setVenue(venue);
				
		//handling dates and times
		try {
			SimpleDateFormat dateFormat = new SimpleDateFormat("MMM dd, yyyy HH:mm:ss", Locale.US);
			dateFormat.setTimeZone(TimeZone.getTimeZone("Asia/Hong_Kong"));
			temp.setStartTime(prepareTime(date[0], time[0], weekDay));
			temp.setEndTime(prepareTime(date[0], time[1], weekDay));
			temp.setStartDate(dateFormat.parse(date[0]+" "+"00:00:00"));
			temp.setEndDate(dateFormat.parse(date[1]+" "+"23:59:59"));
		} catch (ParseException e) {
			return null;
		}
		
		return temp;
	}
	
	/***
	 * Return the formated time.
	 * @param date	the starting and ending date of the course
	 * @param time	the starting and ending time of the course
	 * @param weekday the week day of the course
	 * @return		the formated time
	 * @throws ParseException if an exception occurred
	 */
	private Date prepareTime(String date, String time, Integer weekday) throws ParseException{
		SimpleDateFormat tf = new SimpleDateFormat("MMM dd, yyyy hh:mm a", Locale.US);
		tf.setTimeZone(TimeZone.getTimeZone("Asia/Hong_Kong"));
		
		Date timeObj = new Date();
		timeObj = tf.parse(date+" "+time);
		timeObj = correctTime(timeObj, weekday);
		return timeObj;
	}

	/***
	 * Correct the time for the ICSGenerator.
	 * @param time	
	 * @param weekDay the week day in number
	 * @return		the corrected time
	 */
	private Date correctTime(Date time, Integer weekDay){
		Calendar cal = Calendar.getInstance();
		cal.setTime(time);

		while(cal.get(Calendar.DAY_OF_WEEK) != weekDay){
			cal.add(Calendar.DAY_OF_YEAR, 1);
		}
		return cal.getTime();
	}

	/***
	 * Return the corresponding week day in number.
	 * @param weekDay the week day in character
	 * @return		the week day in number
	 */
	private int getWeekDayByChar(String weekDay) {
		switch(weekDay.toLowerCase()){
		case "u": return 1;
		case "m": return 2;
		case "t": return 3;
		case "w": return 4;
		case "r": return 5;
		case "f": return 6;
		case "s": return 7;
		default: return -1;
		}
	}
}
